package com.yjk1.example.myFirstSofawebBoot.mapping.impl;

import com.yjk1.example.myFirstSofawebBoot.mapping.RegisterMappingException;
import com.yjk1.example.myFirstSofawebBoot.mapping.RequestMappingRegister;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.annotation.PostConstruct;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p> </p>
 *
 * <pre> Created: 2018/11/15 16:47 </pre>
 *
 * @author hlu
 * @version 1.0
 * @since JDK 1.7
 */
@Component
public class RequestMappingRegisterImpl implements RequestMappingRegister {

    /**
     *  用于保存所有Class的Request映射,最外层键为插件名
     */
    private final Map<String,Map<Class<?>,List<RequestMappingInfo>>> mappingsMap = new HashMap<>();

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    private Method getMappingForMethod;

    @PostConstruct
    public void getMappingForMethod(){
        Method getMappingForMethod = ReflectionUtils.findMethod(RequestMappingHandlerMapping.class,
                "getMappingForMethod", Method.class, Class.class);
        getMappingForMethod.setAccessible(true);
        this.getMappingForMethod = getMappingForMethod;
    }


    @Override
    public void registerForControllerClass(Class<?> clazz,Object proxy,String pluginName) throws RegisterMappingException {
        Controller controller = AnnotationUtils.findAnnotation(clazz, Controller.class);
        //如果此bean是Controller，则注册到RequestMappingHandlerMapping里面
        if(controller == null){
            return;
        }
        try {
            Map<Class<?>, List<RequestMappingInfo>> classListMap = this.mappingsMap.get(pluginName);
            Method[] method_arr = clazz.getMethods();
            if (classListMap == null) {
                classListMap = new HashMap<>(method_arr.length);
                mappingsMap.put(pluginName, classListMap);
            }
            List<RequestMappingInfo> mappingInfoList = new ArrayList<>();
            for (Method m_d : method_arr) {
                if (AnnotationUtils.findAnnotation(m_d, RequestMapping.class) != null) {
                    //创建RequestMappingInfo
                    RequestMappingInfo mapping_info = (RequestMappingInfo) getMappingForMethod.invoke(requestMappingHandlerMapping, m_d, clazz);

                    //注册
                    requestMappingHandlerMapping.registerMapping(mapping_info, proxy, m_d);
                    mappingInfoList.add(mapping_info);
                }
            }
            if (!mappingInfoList.isEmpty()) {
                classListMap.put(clazz, mappingInfoList);
            }

        }catch (IllegalAccessException | InvocationTargetException e){
            throw new RegisterMappingException("RequestMapping注册失败！",e);
        }
    }

    @Override
    public void unRegisterForPluginName(String pluginName){
        final Map<Class<?>, List<RequestMappingInfo>> classListMap = this.mappingsMap.get(pluginName);
        for (Map.Entry<Class<?>, List<RequestMappingInfo>> entry : classListMap.entrySet()) {
            for (RequestMappingInfo mappingInfo : entry.getValue()) {
                //反注册
                requestMappingHandlerMapping.unregisterMapping(mappingInfo);
            }
        }
    }
}
